package com.reflect.util;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.util.*;

public class XMLUtil<T> {
    private String className;   //bean标签的class属性(全类名)
    private List<Tag> childTag; //存放子标签的链表

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public List<Tag> getChildTag() {
        return childTag;
    }

    public void setChildTag(List<Tag> childTag) {
        this.childTag = childTag;
    }

    @Override
    public String toString() {
        return "XMLUtil{" +
                "className='" + className + '\'' +
                ", childTag=" + childTag +
                '}';
    }

    public void readXml(String beanName){
        if(beanName == null){
            return;
        }
        //创建reader对象
        SAXReader reader = new SAXReader();
        Document document = null;
        //根据反射获取文件路径
        final String path = XMLUtil.class.getClassLoader().
                getResource("spring.xml").getPath();
        try {
            //加载xml文件
            document = reader.read(new File(path));
        } catch (DocumentException | MalformedURLException e) {
            e.printStackTrace();
        }
        //获取根节点
        final Element rootElement = document.getRootElement();
        //获取迭代器对象
        final Iterator elementIterator = rootElement.elementIterator();
        boolean flag = false;
        //遍历xml
        while (elementIterator.hasNext()){
            //获取标签
            final Element element = (Element) elementIterator.next();
            //判断标签内容是否为bean
            if(element.getName().equals("bean")){
                //获取当前标签中属性
                final List<Attribute> attributes = element.attributes();
                //遍历标签属性
                for (Attribute attribute : attributes) {
                    //如果当前id属性和需要创建的对象一致
                    if(flag && attribute.getName().equals("class")){
                        //取出class属性值
                        className = attribute.getValue();
                        //获取子标签迭代器对象
                        Iterator childElementIterator = element.elementIterator();
                        //为子标签创建对象
                        childTag = new ArrayList<>();
                        //遍历子标签
                        while(childElementIterator.hasNext()){
                            //获取子标签
                            Element childNext = (Element) childElementIterator.next();
                            //创建tag对象
                            Tag tag = new Tag();
                            //设置标签名
                            tag.setTagName(childNext.getName());
//                            System.out.print(childNext.getName() + "->");
                            //获取子标签属性
                            List<Attribute> childAttributes = childNext.attributes();
                            //创建存储子标签属性的map
                            Map<String, String> map = new LinkedHashMap<>();
                            //遍历子标签属性
                            for (Attribute childAttribute : childAttributes) {
                                //为单个子标签属性赋值
                                map.put(childAttribute.getName(), childAttribute.getValue());
                            }
                            //将该list添加到tag对象中
                            tag.setTagProperties(map);
                            //添加tag对象到childTag链表中
                            childTag.add(tag);
                        }
                        break;
                    }
                    //判断属性中的id内容是否为需要创建的bean对象
                    if(attribute.getName().equals("id") && attribute.getValue().equals(beanName)){
                        flag = true;
                    }
                }
            }
            if(flag){
                break;
            }
        }
    }

    public T getBean(String beanName) throws Exception {
        //读取xml文件
        readXml(beanName);
        //如果没有子标签则直接创建对象
        if(childTag.size() == 0){
            final Class<?> aClass = Class.forName(className);
            return (T) aClass.newInstance();
        }
        //如果有子标签通过反射递归创建对象
        return creatObjectByReflect();
    }

    //使用反射创建对象
    public T creatObjectByReflect() throws Exception {
        Class creatClass = null;
        try {
            //将类加在进内存
            creatClass = Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //遍历标签内部
        for (Tag tag : childTag) {
            //如果是property则调用set方法
            if("property".equals(tag.getTagName())){
                //遍历property的每个标签
                final Set<Map.Entry<String, String>> entrySet = tag.getTagProperties().entrySet();
                String MethodName = null;
                for (Map.Entry<String, String> entry : entrySet) {
                    //存储方法名
                    //给方法名赋值
                    if("name".equals(entry.getKey())){
                        MethodName = entry.getValue();
                    }
                    //如果是ref方式
                    if("ref".equals(entry.getKey())){
                        //获取子标签类名
                        XMLUtil xmlUtil = new XMLUtil();
                        System.out.println(MethodName);
                        xmlUtil.readXml(MethodName);
                        final String className = xmlUtil.getClassName();
                        System.out.println(className);
                        //获取该方法的class对象
                        final Class<?> aClass = Class.forName(className);
                        //获取成员变量对应的set方法
                        final Method setMethod = creatClass.getMethod("set" +
                                //将set方法第一个字母转大写
                                MethodName.substring(0,1).toUpperCase() + MethodName.substring(1),aClass);
                        //创建对象
                        final Object newInstance = creatClass.newInstance();
                        //执行set方法
                        final T bean = getBean(entry.getValue());
                        final Object xmlUtilBean = xmlUtil.getBean(entry.getValue());
                        setMethod.invoke(newInstance,xmlUtilBean);
                        return (T) newInstance;
                    }
                    //如果是value方式
                    else if("value".equals(entry.getKey())){
                        //获取子标签类名
                        XMLUtil xmlUtil = new XMLUtil();
                        xmlUtil.readXml(MethodName);
                        final String className = xmlUtil.getClassName();
                        //获取该方法的class对象
                        final Class<?> aClass = Class.forName(className);
                        //获取成员变量对应的set方法
                        final Method setMethod = creatClass.getMethod("set" + MethodName, aClass);
                        //创建对象
                        final Object newInstance = creatClass.newInstance();
                        //执行set方法
                        setMethod.invoke(newInstance,entry.getValue());
                        return (T) newInstance;
                    }
                }
            }
            //如果是constructor-arg则调用构造方法
            else if("constructor-arg".equals(tag.getTagName())){
                //遍历constructor-arg标签的属性
                final Set<Map.Entry<String, String>> entrySet = tag.getTagProperties().entrySet();
                //存储方法名
                String MethodName = null;
                for (Map.Entry<String, String> entry : entrySet) {
                    //给方法名赋值
                    if("name".equals(entry.getKey())){
                        MethodName = entry.getValue();
                    }
                    //将方法名第一个字母变大写
                    //如果是ref方式
                    if("ref".equals(entry.getKey())){
                        //获取子标签类名
                        XMLUtil xmlUtil = new XMLUtil();
                        xmlUtil.readXml(MethodName);
                        final String className = xmlUtil.getClassName();
                        //获取该方法的class对象
                        final Class<?> aClass = Class.forName(className);
                        //获取成员变量对应的构造方法
                        final Constructor constructor = creatClass.getConstructor(aClass);
                        //使用构造方法创建对象
                        final Object xmlUtilBean = xmlUtil.getBean(entry.getValue());
                        final Object newInstance = constructor.newInstance(xmlUtilBean);
                        return (T) newInstance;
                    }
                    //如果是value方式
                    else if("value".equals(entry.getKey())){
                        //获取子标签类名
                        XMLUtil xmlUtil = new XMLUtil();
                        xmlUtil.readXml(MethodName);
                        final String className = xmlUtil.getClassName();
                        //获取该方法的class对象
                        final Class<?> aClass = Class.forName(className);
                        final Constructor constructor = creatClass.getConstructor(aClass);
                        //使用构造方法创建对象
                        final Object newInstance = constructor.newInstance(entry.getValue());
                        return (T) newInstance;
                    }
                }
            }
        }
        return null;
    }
}
